package com.autonavi.yunda.yunji.common.utils.geo;

import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * Created by mengpeng.mp on 2017/9/15.
 */
@Service
public class WKTArea {

    /**
     * 计算面积
     *
     * @param wkt 格式如: 116.572762 40.049263,116.572821 40.050158,116.573792 40.050071,116.574731 40.049993,116.574618 40.049135,116.572762 40.049263
     */
    public static double pointsArea(String wkt) {
        ArrayList<GeoLatLon> points = new ArrayList<>();
        String[] pointList = wkt.split(",");
        for (String point : pointList) {
            String[] pintXY = point.split(" ");
            points.add(new GeoLatLon(pintXY[1], pintXY[0]));
        }
        return pointsArea(points);
    }


    /**
     * 计算面积
     *
     * @param points
     * @return
     */
    public static double pointsArea(ArrayList<GeoLatLon> points) {
        try {
            Double earchWDZC = 40008.08 * 1000;
            Integer pointNum = points.size();
            if (pointNum < 3) {
                return 0;
            }

            Double wd = points.get(0).lat;
            Double s = 0D;
            s = wd * (points.get(pointNum - 1).lon - points.get(1).lon);
            for (Integer i = 1; i < pointNum; i++) {
                s += points.get(i).lat *
                        (points.get(i - 1).lon - points.get((i + 1) % pointNum).lon);
            }
            s = Math.abs(s) / 2 * Math.cos((2 * Math.PI / 360) * wd) * (earchWDZC / 360) * (earchWDZC / 360);
            return s / 1000000.0;
        } catch (Exception e) {

        }
        return 0.0;
    }

    /**
     * 返回points的面积，单位平方公里
     *
     * @param points
     * @return
     */
    public static double areaOfWKTByPoints(ArrayList<GeoLatLon> points) {
        try {
            Double earchWDZC = 40008.08 * 1000;
            Integer pointNum = points.size();
            if (pointNum < 3) {
                return 0;
            }

            Double wd = points.get(0).lat;
            Double s = 0D;
            s = wd * (points.get(pointNum - 1).lon - points.get(1).lon);
            for (Integer i = 1; i < pointNum; i++) {
                s += points.get(i).lat *
                        (points.get(i - 1).lon - points.get((i + 1) % pointNum).lon);
            }
            s = Math.abs(s) / 2 * Math.cos((2 * Math.PI / 360) * wd) * (earchWDZC / 360) * (earchWDZC / 360);
            return s / 1000000.0;
        } catch (Exception e) {

        }
        return 0.0;
    }

    public static double areaOfWKTByBlock(List<String> block_ids) {
        double acc = 0;
        for (String block_id : block_ids) {
            if (block_id.length() == 11) {
                acc += 1;
            } else if (block_id.length() == 13) {
                acc += 0.5 * 0.5;
            } else if (block_id.length() == 15) {
                acc += 0.1 * 0.1;
            } else if (block_id.length() == 17) {
                acc += 0.05 * 0.05;
            } else if (block_id.length() == 19) {
                acc += 0.01 * 0.01;
            }
        }
        return acc;
    }

    public static double areaOfCircle(double radius) {
        return radius * radius * Math.PI;
    }

    public static double calcCoefByArea(List<String> block_ids, double real_area, HashSet<String> margin) {
        int length = (block_ids.get(0).length() - 1) / 2;
        HashMap<Integer, ArrayList<Integer>> index = new HashMap<>();
        int x_min = Integer.MAX_VALUE;
        int y_min = Integer.MAX_VALUE;
        int x_max = 0;
        int y_max = 0;
        for (String block_id : block_ids) {
            String[] xy = block_id.split("_");
            int x = Integer.parseInt(xy[0]);
            int y = Integer.parseInt(xy[1]);
            if (x > x_max) {
                x_max = x;
            }
            if (x < x_min) {
                x_min = x;
            }
            if (y > y_max) {
                y_max = y;
            }
            if (y < y_min) {
                y_min = y;
            }
            if (index.containsKey(x)) {
                index.get(x).add(y);
            } else {
                ArrayList<Integer> tmp = new ArrayList<>();
                tmp.add(y);
                index.put(x, tmp);
            }
            if (index.containsKey(y)) {
                index.get(y).add(x);
            } else {
                ArrayList<Integer> tmp = new ArrayList<>();
                tmp.add(x);
                index.put(y, tmp);
            }
        }
        for (int i = x_min; i <= x_max; i++) {
            int cur_min = Integer.MAX_VALUE;
            int cur_max = 0;
            ArrayList<Integer> tmp = index.get(i);
            if (tmp == null) {
                continue;
            }
            for (Integer each : tmp) {
                if (each > cur_max) {
                    cur_max = each;
                }
                if (each < cur_min) {
                    cur_min = each;
                }
            }
            margin.add(String.format("%0" + length + "d", i) + "_" + String.format("%0" + length + "d", cur_min));
            margin.add(String.format("%0" + length + "d", i) + "_" + String.format("%0" + length + "d", cur_max));
        }
        for (int i = y_min; i <= y_max; i++) {
            int cur_min = Integer.MAX_VALUE;
            int cur_max = 0;
            ArrayList<Integer> tmp = index.get(i);
            if (tmp == null) {
                continue;
            }
            for (Integer each : tmp) {
                if (each > cur_max) {
                    cur_max = each;
                }
                if (each < cur_min) {
                    cur_min = each;
                }
            }
            margin.add(String.format("%0" + length + "d", cur_min) + "_" + String.format("%0" + length + "d", i));
            margin.add(String.format("%0" + length + "d", cur_max) + "_" + String.format("%0" + length + "d", i));
        }
        int m = block_ids.size() - margin.size();
        int n = margin.size();
        double r = real_area / areaOfWKTByBlock(block_ids);
        return (r - 1) * m / n + r;
    }
}
